﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Nine.Serialization;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;

namespace UnitTest
{
    public class MyContext
    {
        private MyContext() { }
        public static readonly MyContext Singleton = new MyContext();
    }

    public class MyContextEx
    {
        private MyContextEx() { }
        public static readonly MyContextEx Singleton = new MyContextEx();
    }

    public struct Box
    {
        public int Width;
        public int Height;
    }

    public static class MyExtension
    {
        public static MyContext GetMyContext(this IServiceProvider serviceProvider)
        {
            return MyContext.Singleton;
        }

        public static MyContextEx GetMyContextEx(this IServiceProvider serviceProvider)
        {
            return MyContextEx.Singleton;
        }

        public static void Write(this BinaryWriter output, Box value)
        {
            output.Write(value.Width);
            output.Write(value.Height);
        }

        public static Box ReadBox(this BinaryReader input)
        {
            return new Box { Width = input.ReadInt32(), Height = input.ReadInt32() };
        }


        public static void Write(this BinaryWriter output, long value)
        {
            LongOverride++;
            output.Write(value);
        }

        public static long ReadLong(this BinaryReader input)
        {
            LongOverride++;
            return input.ReadInt64();
        }

        public static int LongOverride = 0;
    }

    public partial class TestCases
    {
        #region CustomConstructor
        [BinarySerializable]
        public class ETest0
        {
            public string A;
            public ETest0(MyContext context, MyContextEx contextEx) { }
        }

        [TestMethod]
        public void CustomConstructor()
        {
            var obj = new ETest0(MyContext.Singleton, MyContextEx.Singleton);
            obj.A = "asdf";

            var cloned = Clone(obj);
            Assert.AreEqual(obj.A, cloned.A);
        }
        #endregion

        #region BatchInitialize
        [BinarySerializable]
        public class ETest1 : ISupportInitialize
        {
            bool initialized;

            public void BeginInit()
            {
                initialized = true;
            }

            public void EndInit()
            {
                if (initialized)
                    throw new InvalidOperationException();
            }
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void BatchInitialize()
        {
            Clone(new ETest1());
        }
        #endregion

        #region CustomValueTypes
        [BinarySerializable]
        public class ETest2
        {
            public Box Box;
        }

        [TestMethod]
        public void CustomValueTypes()
        {
            var obj = new ETest2 { Box =new Box { Width = 1, Height = 2}};
            
            Clone(obj, cloned =>
            {
                Assert.AreEqual(obj.Box.Width, cloned.Box.Width);
                Assert.AreEqual(obj.Box.Height, cloned.Box.Height);
            });
        }
        #endregion

        #region TypeBehaviorOverride
        [BinarySerializable]
        public class ETest3
        {
            public long Value;
        }

        [TestMethod]
        public void TypeBehaviorOverride()
        {
            var obj = new ETest3 { Value = 100 };
            MyExtension.LongOverride = 0;
            Assert.AreEqual(obj.Value, Clone(obj).Value);
            Assert.AreEqual(2, MyExtension.LongOverride);
        }
        #endregion
    }
}
